/**
 * Copyright (c) 2010-2011 julewa.com.  
 * All rights reserved. 
 * 
 * @author Huang Benhua
 * @date 2011-2-20
 * 
**/
package com.julewa.loading;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.julewa.Client;
import com.julewa.ThreadValue;
import com.julewa.User;

public final class ClientImpl implements Client{
	//
	final ThreadValue<HttpServletRequest> req = new ThreadValue<HttpServletRequest>();
	final ThreadValue<HttpServletResponse> resp = new ThreadValue<HttpServletResponse>();
	//
	public HttpServletRequest getRequest(){
		return req.get();
	}
	public HttpServletResponse getResponse(){
		return resp.get();
	}
	//
	public boolean isAnonimous(){
		return getUser() == null;
	};
	//
	public Object getSession(String key){
		return req.get().getSession(true).getAttribute(key);
	};
	public void setSession(String key, Object value){
		if(value == null){
			req.get().getSession(true).removeAttribute(key);
		}else{
			req.get().getSession(true).setAttribute(key, value);
		}
	};
	private static long id_max = 0;
	public long generateIdentifier(){
		if(id_max == Long.MAX_VALUE || id_max < 0){
			id_max = 0;
		}
		return  ++ id_max ;
	};
	//
	public void setUser(User user){
		setSession("", user);
	};
	public User getUser(){
		return (User)getSession("");
	};
	//content type?
	public String getParameter(String key){
		return req.get().getParameter(key);
	};
	public String[] getParameters(String key){
		return req.get().getParameterValues(key);
	};
	@SuppressWarnings("unchecked")
	public Set<String> getParameterNames(){
		return req.get().getParameterMap().keySet();
	};
	//
	public String getContentType(){
		return resp.get().getContentType();
	};
	public void setContentType(String contentType){
		resp.get().setContentType(contentType);
	};
	//
	public Object getRequest(String key){
		return req.get().getAttribute(key);
	};
	public void setRequest(String key, Object value){
		if(value == null){
			req.get().removeAttribute(key);
		}else{
			req.get().setAttribute(key, value);
		}
	};
	
	//
	public String getAddress(){
		return req.get().getRemoteAddr();
	}
	public String getHostname(){
		return req.get().getRemoteHost();
	}
	public String getUriRoot(){
		return (String)req.get().getAttribute(RESTNameMapper.URI_ROOT);
	}
	public String getRestString(){
		return (String)req.get().getAttribute(RESTNameMapper.REST_STRING);
	}
//	public String getResponseType(){
//		return (String)req.get().getAttribute("_REST_SUF_");
//	}
//	public String getContentType(){
//		return resp.get().getContentType();
//	}
	
	class ThreadMap extends ThreadValue<Map<String,String>>{
	    public void initialize(){
	        Map<String, String> m = this.get();
	        if(m == null){
	        	this.set(new HashMap<String,String>());
	        }else{
	        	m.clear();
	        }
	    }
	    public boolean isNotEmpty(){
	    	Map<String, String> m = this.get();
	    	return m != null && !m.isEmpty();
	    }
	};
	
	class ThreadList extends ThreadValue<List<String>>{
	    public void initialize(){
	        List<String> m = this.get();
	        if(m == null){
	        	this.set(new ArrayList<String>());
	        }else{
	        	m.clear();
	        }
	    }
	    public boolean isNotEmpty(){
	    	List<String> m = this.get();
	    	return m != null && !m.isEmpty();
	    }
	};
	
	final ThreadMap fmessages = new ThreadMap();
	final ThreadMap ferrors = new ThreadMap();
	final ThreadList messages = new ThreadList();
	final ThreadList errors = new ThreadList();
	
	public Map<String,String> getFieldMessages(){
		return fmessages.get();
	}
	
	public Map<String, String> getFieldErrors(){
		return ferrors.get();
	}
	
	@Override
	public String getMessage(String key) {
		return fmessages.get().get(key);
	}
	@Override
	public List<String> getMessages() { 
		return messages.get();
	}
	@Override
	public String getError(String key) { 
		return ferrors.get().get(key);
	}
	
	@Override
	public List<String> getErrors() { 
		return errors.get();
	}

	@Override
	public void setMessage(String key, String message) {
		fmessages.get().put(key, message);
	}
	@Override
	public void putMessage(String message) {
		messages.get().add(message);
	}
	@Override
	public void setError(String key, String error) {
		ferrors.get().put(key, error);
	}
	@Override
	public void putError(String error) {
		errors.get().add(error);
	}
	
	private String fmt(String m, Object...args){
		if(args==null || args.length < 1)return m;
		return String.format(m, args);
	}
	@Override
	public void setMessage(String key, String message, Object...args) {
		fmessages.get().put(key, fmt(message, args));
	}
	@Override
	public void putMessage(String message, Object...args) {
		messages.get().add(fmt(message, args));
	}
	@Override
	public void setError(String key, String error, Object...args) {
		ferrors.get().put(key, fmt(error, args));
	}
	@Override
	public void putError(String error, Object...args) {
		errors.get().add(fmt(error, args));
	}
	
	//
	public boolean hasError(){
		return ferrors.isNotEmpty() || errors.isNotEmpty();
	};
	public boolean hasMessage(){
		return fmessages.isNotEmpty() || messages.isNotEmpty();
	};
}
